撞車事件(Day 15)之後,我動手蓋工作帳本。構想很宏大,實作很用力,下場很難看。今天寫這個叫我承認「設計錯了」的案子。
當時我認為工作帳本是個敏感的東西:agent 可以在任何時間認領工作、更新狀態,如果沒有足夠的防護,兩個人同時寫同一張卡也可能又是一次撞車。所以我做了完整的防護層:認領要透過 request file,寫入要走 durable queue,每筆變更附 receipt,還有 session binding 確保「只有當初認領的那個 session」能更新自己的狀態。
這套東西不是亂做的。每一層都對應一個真實的擔憂:併發寫入是同事撞車(撞車事件本身就是擔憂的來源)、臨時斷線要能補投遞、跨 session 的身份要驗證。單獨看每一層都有道理。
問題是總加起來的樣子。每做一次很小的更新,要經過 request file、queue、receipt、binding 四個層。每一層都可能出錯,每一層的成本最後都回到人身上:我要花時間排隊等它跑完、查它有沒有收下、看它認不認我的身份。帳本是為了讓我早上起來知道每件事的狀態,但我每天花在維護帳本本身的時間,已經多於看它。
八月十日我做了裁決:V2 的整套 ensure-and-claim 計畫,連同 queue、receipt、binding,全部作廢。取而代之的方案簡單到不像話:讓 CLI 直接同步呼叫帳本。有 API、就有資料、立刻返回結果。不再有非同步的隊伍,不再有需要補投遞的回執,不再有需要驗的 session binding。
這個決定其實是有前提條件的,不是單純的「簡單就是好」。在這例裡我把帳本重新定義為:這是一個內部可信的工作看板,不是一個要面對外部攻擊者的需要防禦的系統。它服務的人只有我一個,連進來的 agent 也全部是我管理的。安全的角度看,它需要的不是防護,是可靠。
而可靠的東西要能讓人快速改并且馬上看到結果。同步的 CLI 做到這點,非同步的 queue 做不到。
我把這個案例寫進後來的規則,標記它是一個「復盤時最容易低估的成本:延遲」。每次排隊可能只有幾秒,但一天排五十次,加上排完不能確定投遞成功,真正的成本是每次都要停下來確認一次。
規則現在這樣寫:內部工具的第一版,先用最直接、最同步、最沒有中間層的實作,它被使用者砸的次數最多,最需要能快速迭代;防護層等它出過事再加。而這條規則的反面教訓,就是 V1 的設計:我所有的擔憂都不是真的,每層防護都是為不存在的敵人蓋的牆。
帳本簡化之後,新的問題是有些使用者不是人而是自動化的 hook,同步的 CLI 對它們來說還是太重。這個問題我改天再寫。
帳本有了直連的 CLI,實際用起來之後才發現更大的問題不在技術,在概念:帳本上出現了三種完全不同的東西,我當時把它們混在一個系統裡。明天講這個。